package com.finger.forest;

import android.app.ProgressDialog;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
import com.esri.arcgisruntime.concurrent.Job;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.Feature;
import com.esri.arcgisruntime.data.FeatureCollection;
import com.esri.arcgisruntime.data.FeatureCollectionTable;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ServiceFeatureTable;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.layers.FeatureCollectionLayer;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.GeoElement;
import com.esri.arcgisruntime.mapping.view.DefaultMapViewOnTouchListener;
import com.esri.arcgisruntime.mapping.view.Graphic;
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
import com.esri.arcgisruntime.mapping.view.IdentifyGraphicsOverlayResult;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.portal.Portal;
import com.esri.arcgisruntime.portal.PortalItem;
import com.esri.arcgisruntime.security.AuthenticationManager;
import com.esri.arcgisruntime.security.DefaultAuthenticationChallengeHandler;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;
import com.esri.arcgisruntime.tasks.offlinemap.GenerateOfflineMapJob;
import com.esri.arcgisruntime.tasks.offlinemap.GenerateOfflineMapParameters;
import com.esri.arcgisruntime.tasks.offlinemap.GenerateOfflineMapResult;
import com.esri.arcgisruntime.tasks.offlinemap.OfflineMapTask;
import com.finger.forest.base.BaseActivity;
import com.finger.forest.base.BaseApi;
import com.finger.forest.base.CommonKey;
import com.finger.forest.base.SystemConfig;
import com.finger.forest.utils.encode.PrefsUtil;
import com.jakewharton.rxbinding2.view.RxView;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;

/**
 * 离线地图
 */
public class OfflineMapActivity extends BaseActivity {

    private static final String TAG = "OfflineMapActivity";

    private MapView mMapView;

    private GraphicsOverlay mGraphicsOverlay;

    private Graphic mDownloadArea;

    @BindView(R.id.ivLeft)
    ImageView ivLeft;
    @BindView(R.id.ivRight)
    ImageView ivRight;
    @BindView(R.id.btn_operate)
    Button operateBtn;

    /**
     * 责任区ID
     */
    String areaId;

    @Override
    protected int setView() {
        return R.layout.activity_offline_map;
    }

    @Override
    protected void receiveData() {

    }

    @Override
    protected void initializeView() {
        mMapView = findViewById(R.id.mapView);
        // handle authentication with the portal
        AuthenticationManager.setAuthenticationChallengeHandler(new DefaultAuthenticationChallengeHandler(this));
        setupMap();

        // create a graphics overlay for the map view
        mGraphicsOverlay = new GraphicsOverlay();
        mMapView.getGraphicsOverlays().add(mGraphicsOverlay);

        // create a graphic to show a box around the extent we want to download
        mDownloadArea = new Graphic();
        mGraphicsOverlay.getGraphics().add(mDownloadArea);
        SimpleLineSymbol simpleLineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 2);
        mDownloadArea.setSymbol(simpleLineSymbol);

        // update the download area box whenever the viewpoint changes
        mMapView.addViewpointChangedListener(viewpointChangedEvent -> {
            // upper left corner of the area to take offline
            android.graphics.Point minScreenPoint = new android.graphics.Point(200, 200);
            // lower right corner of the downloaded area
            android.graphics.Point maxScreenPoint = new android.graphics.Point(mMapView.getWidth() - 200,
                    mMapView.getHeight() - 200);
            // convert screen points to map points
            Point minPoint = mMapView.screenToLocation(minScreenPoint);
            Point maxPoint = mMapView.screenToLocation(maxScreenPoint);
            // use the points to define and return an envelope
            if (minPoint != null && maxPoint != null) {
                Envelope envelope = new Envelope(minPoint, maxPoint);
                mDownloadArea.setGeometry(envelope);
            }
        });

        //获取责任区ID
        areaId = PrefsUtil.getString(OfflineMapActivity.this,CommonKey.AREA_ID);

        //添加巡护责任区图层
        //addAreaLayerById();

        //初始化点击事件
        clicks();
    }

    private void setupMap() {
        if (mMapView != null) {
            ArcGISRuntimeEnvironment.setLicense(CommonKey.LICENSE);
            mMapView.setAttributionTextVisible(false);
            Basemap.Type basemapType = Basemap.Type.IMAGERY;
            /*ArcGISMap map = new ArcGISMap(basemapType, SystemConfig.latitude, SystemConfig.longitude, SystemConfig.mapLevel);*/

            // create a portal item with the itemId of the web map
            Portal portal = new Portal("https://www.arcgis.com", false);
            PortalItem portalItem = new PortalItem(portal, "acc027394bc84c2fb04d1ed317aac674");

            // create a map with the portal item
            ArcGISMap map = new ArcGISMap(portalItem);
            mMapView.setMap(map);
            //添加责任区图层
            //mMapView.getMap().getOperationalLayers().add(0, featureCollectionLayerArea);
        }
    }

    //面图层添加、删除
    ServiceFeatureTable serviceFeatureTableArea = new ServiceFeatureTable(BaseApi.GIS_SERVER_URL + BaseApi.GIS_POLYGON);
    FeatureCollectionLayer featureCollectionLayerArea = new FeatureCollectionLayer(new FeatureCollection());
    private void addAreaLayerById() {
        //面图层样式
        SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, 0x883893ED, null);
        SimpleRenderer areaRenderer = new SimpleRenderer(fillSymbol);

        QueryParameters queryParams = new QueryParameters();
        queryParams.setWhereClause("OBJECTID = "+ areaId);

        final ListenableFuture<FeatureQueryResult> queryResult = serviceFeatureTableArea.queryFeaturesAsync(queryParams);
        queryResult.addDoneListener(() -> {
            try {
                // call get on the future to get the result
                FeatureQueryResult result = queryResult.get();

                //create a feature collection table from the query results
                FeatureCollectionTable featureCollectionTable = new FeatureCollectionTable(result);
                featureCollectionTable.setRenderer(areaRenderer);

                //create a feature collection from the above feature collection table
                FeatureCollection featureCollection = new FeatureCollection();
                featureCollection.getTables().add(featureCollectionTable);

                //create a feature collection layer
                featureCollectionLayerArea = new FeatureCollectionLayer(featureCollection);

                //add the layer to the operational layers array
                mMapView.getMap().getOperationalLayers().set(0,featureCollectionLayerArea);

                // check there are some results
                Iterator<Feature> resultIterator = result.iterator();
                if (resultIterator.hasNext()) {
                    // get the extent of the first feature in the result to zoom to
                    Feature feature = resultIterator.next();
                    Envelope envelope = feature.getGeometry().getExtent();
                    //定位到责任区
                    mMapView.setViewpointGeometryAsync(envelope, 10);

                    //设置待下载离线地图区域
                    //mDownloadArea.setGeometry(envelope);
                } else {
                    Toast.makeText(OfflineMapActivity.this, "未查询到责任区", Toast.LENGTH_LONG).show();
                }
            } catch (InterruptedException | ExecutionException e) {
                Log.e(TAG, "Error in FeatureQueryResult: " + e.getMessage());
            }
        });
    }

    private void clicks() {
        //返回
        RxView.clicks(ivLeft).throttleFirst(1, TimeUnit.SECONDS).subscribe(o -> {
            finish();
        });

        //刷新
        RxView.clicks(ivRight).throttleFirst(1, TimeUnit.SECONDS).subscribe(o -> {
            //初始化加载同步会商数据
            //initFeature();
        });

        ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("Generate offline map job");
        progressDialog.setMessage("Taking map offline...");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setIndeterminate(false);
        progressDialog.setProgress(0);
        //下载离线地图
        RxView.clicks(operateBtn).throttleFirst(1, TimeUnit.SECONDS).subscribe(o -> {
            progressDialog.show();

            // delete any offline map already in the cache
            String tempDirectoryPath = getExternalCacheDir() + File.separator + "offlineMap";
            deleteDirectory(new File(tempDirectoryPath));

            // specify the extent, min scale, and max scale as parameters
            double minScale = mMapView.getMapScale();
            double maxScale = mMapView.getMap().getMaxScale();
            // minScale must always be larger than maxScale
            if (minScale <= maxScale) {
                minScale = maxScale + 1;
            }
            GenerateOfflineMapParameters generateOfflineMapParameters = new GenerateOfflineMapParameters(
                    mDownloadArea.getGeometry(), minScale, maxScale);
            // set job to cancel on any errors
            generateOfflineMapParameters.setContinueOnErrors(false);

            // create an offline map offlineMapTask with the map
            OfflineMapTask offlineMapTask = new OfflineMapTask(mMapView.getMap());

            // create an offline map job with the download directory path and parameters and start the job
            GenerateOfflineMapJob job = offlineMapTask.generateOfflineMap(generateOfflineMapParameters, tempDirectoryPath);

            // replace the current map with the result offline map when the job finishes
            job.addJobDoneListener(() -> {
                if (job.getStatus() == Job.Status.SUCCEEDED) {
                    GenerateOfflineMapResult result = job.getResult();
                    mMapView.setMap(result.getOfflineMap());
                    mGraphicsOverlay.getGraphics().clear();
                    operateBtn.setEnabled(false);
                    Toast.makeText(this, "Now displaying offline map.", Toast.LENGTH_LONG).show();
                } else {
                    String error = "Error in generate offline map job: " + job.getError().getAdditionalMessage();
                    Toast.makeText(this, error, Toast.LENGTH_LONG).show();
                    Log.e(TAG, error);
                }
                progressDialog.dismiss();
            });

            // show the job's progress with the progress dialog
            job.addProgressChangedListener(() -> progressDialog.setProgress(job.getProgress()));

            // start the job
            job.start();

        });

    }

    @Override
    protected void loadDataFromServer() {

    }

    @Override
    public void onPause() {
        super.onPause();
        // pause MapView
        mMapView.pause();
    }

    @Override
    public void onResume() {
        super.onResume();
        // resume MapView
        mMapView.resume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // dispose MapView
        mMapView.dispose();
    }

    private static void deleteDirectory(File file) {
        if (file.isDirectory())
            for (File subFile : file.listFiles()) {
                deleteDirectory(subFile);
            }
        if (!file.delete()) {
            Log.e(TAG, "Failed to delete file: " + file.getPath());
        }
    }

}